package com.yskj.mwk.utils;


import com.fasterxml.jackson.databind.JsonNode;
import com.yskj.mwk.config.WechatUrlConfig;
import com.yskj.mwk.config.WxpayConfig;
import org.springframework.core.io.ClassPathResource;

import java.io.*;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 签名工具类
 *
 * @Author: albc
 * @Date: 2024/12/20/16:00
 * @Description: good good study,day day up
 */
public class WechatPayUtils {


    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

    private static final String KEY_ALGORITHM = "RSA";


    /**
     * 获取私钥
     *
     * @param filename 私钥文件路径
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey(String filename) throws IOException {
        InputStream inputStream = new ClassPathResource(filename
                .replace("classpath:", "")).getInputStream();
        String content = new BufferedReader(new InputStreamReader(inputStream))
                .lines().collect(Collectors.joining(System.lineSeparator()));
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }


    /**
     * 获取公钥
     *
     * @param filename
     * @return
     */
    public static String getPublicKey(String filename) throws IOException {
        InputStream inputStream = new ClassPathResource(filename
                .replace("classpath:", "")).getInputStream();
        String content = new BufferedReader(new InputStreamReader(inputStream))
                .lines().collect(Collectors.joining(System.lineSeparator()));
        String publicKey = content.replace("-----BEGIN CERTIFICATE-----", "")
                .replace("-----END CERTIFICATE-----", "")
                .replaceAll("\\s+", "");
        return publicKey;
    }


    /**
     * 生成token 也就是生成签名
     *
     * @param method
     * @param url
     * @param body
     * @return
     * @throws Exception
     */
    public static String getToken(String method, URL url, String body) throws Exception {
        String nonceStr = getNonceStr();
        long timestamp = System.currentTimeMillis() / 1000;
        String message = buildMessage(method, url, timestamp, nonceStr, body);
        String signature = sign(message.getBytes("utf-8"));

        return "WECHATPAY2-SHA256-RSA2048 " + "mchid=\"" + WxpayConfig.mchId + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + WxpayConfig.mchSerialNo + "\","
                + "signature=\"" + signature + "\"";
    }


    /**
     * 获取平台证书
     *
     * @return
     */
    public static Map<String, X509Certificate> refreshCertificate() throws Exception {
        Map<String, X509Certificate> certificateMap = new HashMap();
        // 1: 执行get请求
        JsonNode jsonNode = WxHttpUtils.doGet(WechatUrlConfig.CERTIFICATESURL);
        // 2: 获取平台验证的相关参数信息
        JsonNode data = jsonNode.get("data");
        if (data != null) {
            for (int i = 0; i < data.size(); i++) {
                JsonNode encrypt_certificate = data.get(i).get("encrypt_certificate");
                //对关键信息进行解密
                AesUtil aesUtil = new AesUtil(WxpayConfig.v3Key.getBytes());
                String associated_data = encrypt_certificate.get("associated_data").toString().replaceAll("\"", "");
                String nonce = encrypt_certificate.get("nonce").toString().replaceAll("\"", "");
                String ciphertext = encrypt_certificate.get("ciphertext").toString().replaceAll("\"", "");
                //证书内容
                String certStr = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
                //证书内容转成证书对象
                CertificateFactory cf = CertificateFactory.getInstance("X509");
                X509Certificate x509Cert = (X509Certificate) cf.generateCertificate(
                        new ByteArrayInputStream(certStr.getBytes("utf-8"))
                );
                String serial_no = data.get(i).get("serial_no").toString().replaceAll("\"", "");
                certificateMap.put(serial_no, x509Cert);
            }
        }
        return certificateMap;
    }


    /**
     * 生成签名
     *
     * @param message
     * @return
     * @throws Exception
     */
    public static String sign(byte[] message) throws Exception {
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(getPrivateKey(WxpayConfig.privateKeyPath));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }


    /**
     * 验签方法
     *
     * @param data      验签数据
     * @param publicKey 公钥
     * @param sign      签名
     * @return
     * @throws Exception
     */
    public static boolean verifyByPublicKey(byte[] data, String publicKey, String sign) throws Exception {
        byte[] keyBytes = decryptBASE64(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(data);
        return signature.verify(decryptBASE64(sign)); // 验证签名
    }

    public static void main(String[] args) throws Exception {
        String content="-----BEGIN CERTIFICATE-----\n" +
                "MIIEFDCCAvygAwIBAgIUTUgJS4pdIWbgOtQ+19eT8Ogyvy8wDQYJKoZIhvcNAQEL\n" +
                "BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\n" +
                "FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg\n" +
                "Q0EwHhcNMjUwMjA1MDMzODAwWhcNMzAwMjA0MDMzODAwWjBuMRgwFgYDVQQDDA9U\n" +
                "ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl\n" +
                "bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGEwJDTjERMA8GA1UEBwwIU2hlblpo\n" +
                "ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwzo0cLxwL16BzFwbp\n" +
                "RykcPs0ML0ot703XSsvwJDpcbHZBAHn6F/gVDcCAv6tANVgL3x2MZvQknfNf9DAi\n" +
                "ew665LbaLqy+FAlBCoNli+/SMwSGcDYLbZmGiYDK9ypIrXYma+BoZxW66nBe8/MY\n" +
                "Fg+U3CrnyJsPv4yFIY9wOrSgggY+u1A3NREgDkKSFWdAr9UikUl78v/P0FJvaUoZ\n" +
                "TL0YtWpEetmDlguuNNBBFspNbBsgGSzsA+cPC36sqNPH4uZP8Myn5uGK39axksrF\n" +
                "zOk5AxMBWdW/8sHcZxAA+r01xCQdP+AcCQa1TIvmtqrJELFu/aAA7cT/gMrOY0hp\n" +
                "8PyRAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB\n" +
                "kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv\n" +
                "aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4\n" +
                "RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0\n" +
                "MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAoV61lXylGDFX5Fx09Wjal2278GY+HC6r\n" +
                "WsQNR2suqBg1yVJZXr/XI5OYUe3bjD47DICCxTo3XuEg+Tlgnp2n+56zaGzMI8o5\n" +
                "1JOsD/Q3dj5Enrj/rZD9skhhrwIiJWNPDVFjDwgIbdK30zftRrrFFibAyiLBoEH9\n" +
                "de/nnmQvBcooRKRZNOxc2aasPjVP+u4RQL3jwXS2xVnmfe4NShoGnYhGHkjoMTxt\n" +
                "uGCpAcqanE/CqxLOGpKvcLEuKKBkoCRJBgDobM1XHhLdnugK5GbuHJmISmIF1XOb\n" +
                "Ff7mx9sRj2b26jL4JkQqIiiz835WhalDrjTzD/o48DHM5mTtoLebFQ==\n" +
                "-----END CERTIFICATE-----";
        String publicKey = content.replace("-----BEGIN CERTIFICATE-----", "")
                .replace("-----END CERTIFICATE-----", "")
                .replaceAll("\\s+", "");
        System.out.println(publicKey);
        //String publicKey="MIIEITCCAwmgAwIBAgIUH1LeFtnNN4R5GFjLQG9TiXY2C50wDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsTFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3QgQ0EwHhcNMjUwMjA1MDMzODAxWhcNMzAwMjA0MDMzODAxWjB7MRMwEQYDVQQDDAoxNzAyNTY5MzU1MRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xJzAlBgNVBAsMHua1t+WNl+Wwj+m5heenkeaKgOaciemZkOWFrOWPuDELMAkGA1UEBhMCQ04xETAPBgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Hv/ffBHFM42gK5J8mOQ3nSUoGXQxzdbQUR27DJ7XBJhwugsQVY3N6Q9x/kk0jH9QHYKbOO593iDcdQ6zdfJLbLP2a2GUNYUSc/U8j7cjTl3FQ/6EzguBAkEyP1GkbmCNsNGGyvuBUdtYPw/4Mfqrhsa1WcKoeeTBB8a53png1Z0W2oBybRxLYqpernJfr9vrw5U95tbYnGP0nN0j2GiDazKSo/e1BkCACvxDDN+uyuFOwW6cymCTL/ByEUCzzI+xgnhpJZC/9VPv8FmA7SepiZPgVv7vLKX3U3+3rvl3dbwMnl7U+O7xIioUN6uH9Cm43D1nde7slKiktLf7XwxiwIDAQABo4G5MIG2MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgP4MIGbBgNVHR8EgZMwgZAwgY2ggYqggYeGgYRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDImc2c9SEFDQzQ3MUI2NTQyMkUxMkIyN0E5RDMzQTg3QUQxQ0RGNTkyNkUxNDAzNzEwDQYJKoZIhvcNAQELBQADggEBAD6kUbEoE1D5x4Dq5s3rRF4r67xMdGWL2f0D5UQnamAT3976CaquIzoBwsow+FS0CugOH8N8fPSyvj/lxYNT8x1vttyfAVKyE14H3mDA1V2rOFkwsYIPNKojeBcWEpevKFfjUt6gSL0Igi+luEaEfhERiGAeD23xKhOPzgOAUlCzk8YLaecnULEpLTp+te707tK5NUBRyCv6lq7bCyZhr/v9NzkqaPvytne5JUCjzd8bFG3filZnVszGW1I22f6IN5dc0PiT/4HUCvzcQ3hhgjQPNiJTW9s1XoBh709FxkUiptRpDdV1qXYqq4eepA75LfCyYuUCE38HrtClPcyTPaw=";
        String timestamp="1738985291";
        String nonce="ZhduAzXHB8mY1k8wLoRlKg9KdDdTzc0y";
        String data="{\"id\":\"2714c6db-840e-5946-83fb-4712930ce0ed\",\"create_time\":\"2025-02-08T11:28:11+08:00\",\"resource_type\":\"encrypt-resource\",\"event_type\":\"TRANSACTION.SUCCESS\",\"summary\":\"支付成功\",\"resource\":{\"original_type\":\"transaction\",\"algorithm\":\"AEAD_AES_256_GCM\",\"ciphertext\":\"15sk4RjnVhvrTc8pplXuIKk6h4Z7FIc33rD2O6+FsVdQY2Gh5wcvrqCEUci8TsBYlJf4CPPVFS2c7Wt4cHSCyo/mhmUTdkurzWsGLsFbXPi4SGfBXHhU1CUUoSh7Jw3e2ScS5VADAa6oNLXsnS67Nte4smxzFWyE35526Wkcz7wa69+A1FnJsIZ622wb1DXT9kSUL2C9mzTFsy3wOqbfbtCZbdkyTHNwuqZgS+DST+klxXtQxRjlBpgvSVbVrs5yFX+MS1vb9Q7OOLMU1Ns4FcxqGebbQ99e32NQOGzdpYjo8A55FKj1xtvp6TTAY37aC+NdgFT4apXWZwYC/Cvv3RX4QHmyO4BO0w2GnQpYI5QuzJ4xV3EgCiRdErq61IIIKG0o2I44TPO5kANVxd+p11OK5wOaAXF2fDpMezks7FQPKUvH573uRxhvp0PFHNrx0mjlrW8mIIzH98b9vU2rkL78r6Q0XuXIiwOPR0iO9FkaZXtLqQ7fEVz0h64bOXAMPba2l3i9vIgoWOoZXtMK53ct4KiZHLfslAlLkAxOZufaCVgY5quYLBiKMdzHH9ltf+B+ng==\",\"associated_data\":\"transaction\",\"nonce\":\"Rd5JefvDkCPs\"}}";
        String message = timestamp + "\n" + nonce + "\n" + data + "\n";
        verifyByPublicKey2(message.getBytes(),publicKey,"COv83e34uSjJ0yWRKzrnltJlqHlMC/ayPdtmT6rjJ3kMPkT0xXRxyx923Y8RUqApVBRm9wRBruCvx+D9Qkj4rOJ7rMMUkIn5zglFpG3JTypNtLFAcxv8/a5BK0AR+jsTljZ0ysv5oaJxAbQNiYp70Ebpa3Zj+QSkBOCrDKQatDbpsoRiMq6vEKUtynlFfALgtx21/kS20gZJienG82r0MH/IHA4DQUerT0h64X0jyNngfyaImnUGxpsDKRaDar/oJBH5+RXAmwxx4Od/0n5X6dSlLjCLHMHiig/yzQ+hwSoQJPmt0dC8itoxrvssjPWC33YIclsTDfQodGddZHS2uw==");
    }

    public static boolean verifyByPublicKey2(byte[] message, String publicKeyStr, String signature) throws Exception {

        // 转换 PEM 格式公钥为 PublicKey 对象
        PublicKey publicKey = convertPEMToPublicKey(publicKeyStr);

        // 验证签名
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initVerify(publicKey);
        sig.update(message);
        return sig.verify(Base64.getDecoder().decode(signature));
    }

    private static PublicKey convertPEMToPublicKey(String pemKey) throws GeneralSecurityException {

        byte[] encoded = Base64.getDecoder().decode(pemKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
        System.out.println(keySpec);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        System.out.println(keyFactory);
        return keyFactory.generatePublic(keySpec);
    }


    public static byte[] decryptBASE64(String data) {
        return org.apache.commons.codec.binary.Base64.decodeBase64(data);
    }

    /**
     * 生成签名串
     *
     * @param method
     * @param url
     * @param timestamp
     * @param nonceStr
     * @param body
     * @return
     */
    public static String buildMessage(String method, URL url, long timestamp, String nonceStr, String body) {
        String canonicalUrl = url.getPath();
        if (url.getQuery() != null) {
            canonicalUrl += "?" + url.getQuery();
        }
        return method + "\n"
                + canonicalUrl + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }


    /**
     * 生成随机数
     *
     * @return
     */
    public static String getNonceStr() {
        return UUID.randomUUID().toString()
                .replaceAll("-", "")
                .substring(0, 32);
    }


    /**
     * 拼接参数
     *
     * @return
     */

    public static String buildMessageTwo(String appId, long timestamp, String nonceStr, String packag) {
        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + packag + "\n";
    }

}


